using BackData;
using Domain;
using Domain.Quality;
using Domain.工艺工序;
using Domain.生产订单;
using Infratructure;
using MediatR;
using Microsoft.Identity.Client;
using SqlSugar;
using Team.API.Applocation.Command.排程;
using Yitter.IdGenerator;

namespace Team.API.Applocation.Hanldler.排程
{
    public class CreateProductionCommandHandler : IRequestHandler<CreateProductionCommand, APIResult<int>>
    {
        private readonly IRepository<Productionschedulemodel> productionRep;
        private readonly IRepository<OrderModel> orderRep;
        private readonly IRepository<Makestepmodel> stepRep;
        private readonly IRepository<Equipmentmodel> equipRep;

        public CreateProductionCommandHandler(
            IRepository<Productionschedulemodel> productionRep,
            IRepository<OrderModel> orderRep,
            IRepository<Makestepmodel> stepRep,
            IRepository<Equipmentmodel> equipRep)
        {
            this.productionRep = productionRep;
            this.orderRep = orderRep;
            this.stepRep = stepRep;
            this.equipRep = equipRep;
        }

        public async Task<APIResult<int>> Handle(CreateProductionCommand request, CancellationToken cancellationToken)
        {
            try
            {
                // 获取当前排程计数（用于生成排程编号）
                var currentCount = await productionRep.GetAll().CountAsync(cancellationToken) + 1;

                // 获取待排程订单（状态为0：待排程）
                var pendingOrders = await orderRep.GetAll()
                    .Where(x => x.Orderstatus == 0 && x.IsDel == false)
                    .OrderBy(x => x.Id) // 按创建时间排序，先进先出
                    .ToListAsync(cancellationToken);

                if (!pendingOrders.Any())
                {
                    return APIResult<int>.Ok("没有待排程订单", 0);
                }

                // 1. 先获取所有可用的工艺工序（已启用且未删除）
                var availableProcessSteps = await stepRep.GetAll()
                    .Where(x => x.IsDel == false && x.IsUse == true)
                    .ToListAsync(cancellationToken);

                if (!availableProcessSteps.Any())
                {
                    return APIResult<int>.Faile("没有可用的工艺工序，无法进行排程");
                }

                // 2. 通过工艺工序获取对应的设备ID
                var equipmentIds = availableProcessSteps.Select(x => x.EquipmentId).Distinct().ToList();

                // 3. 加载这些设备的详细信息
                var allEquipments = await equipRep.GetAll()
                    .Where(x => x.IsDel == false && equipmentIds.Contains(x.Id))
                    .ToListAsync(cancellationToken);

                if (!allEquipments.Any())
                {
                    return APIResult<int>.Faile("工艺工序关联的设备不存在或已删除");
                }

                // 4. 获取所有工艺工序的ID
                var processStepIds = availableProcessSteps.Select(x => x.Id).ToList();

                // 5. 通过工艺工序获取现有排程（判断工艺工序的使用状态）
                var existingSchedules = await productionRep.GetAll()
                    .Where(x => x.IsDel == false && processStepIds.Contains(x.Makestepid))
                    .OrderByDescending(x => x.Planendtime)
                    .ToListAsync(cancellationToken);

                // 6. 创建工艺工序到设备的映射
                var processStepEquipmentMap = availableProcessSteps.ToDictionary(x => x.Id, x => x.EquipmentId);

                // 7. 创建设备到工艺工序的映射（用于查找）
                var equipmentProcessMap = availableProcessSteps
                    .GroupBy(x => x.EquipmentId)
                    .ToDictionary(g => g.Key, g => g.First());

                // 8. 创建工艺工序时间线跟踪器（记录每个工艺工序的下次可用时间）
                var processStepTimeline = new Dictionary<long, DateTime>();
                var baseStartTime = DateTime.Now.AddDays(1).Date.AddHours(8); // 基准开始时间：明天早上8点

                foreach (var processStep in availableProcessSteps)
                {
                    // 查找该工艺工序的最后一条排程记录
                    var lastSchedule = existingSchedules
                        .Where(x => x.Makestepid == processStep.Id)
                        .OrderByDescending(x => x.Planendtime)
                        .FirstOrDefault();

                    if (lastSchedule != null && lastSchedule.Planendtime > DateTime.Now)
                    {
                        // 如果工艺工序使用中（有未来的排程），下次开始时间为上次结束时间的第二天早上8点
                        var nextDay = lastSchedule.Planendtime.AddDays(1).Date.AddHours(8);
                        processStepTimeline[processStep.Id] = nextDay;
                    }
                    else
                    {
                        // 工艺工序空闲，使用基准开始时间（明天早上8点）
                        processStepTimeline[processStep.Id] = baseStartTime;
                    }
                }

                // 9. 创建设备时间线（通过工艺工序状态推导）
                var equipmentTimeline = new Dictionary<long, DateTime>();
                foreach (var equipment in allEquipments)
                {
                    // 找到该设备对应的工艺工序
                    var processStep = availableProcessSteps.FirstOrDefault(x => x.EquipmentId == equipment.Id);
                    if (processStep != null && processStepTimeline.ContainsKey(processStep.Id))
                    {
                        equipmentTimeline[equipment.Id] = processStepTimeline[processStep.Id];
                    }
                    else
                    {
                        equipmentTimeline[equipment.Id] = baseStartTime;
                    }
                }

                var scheduleModels = new List<Productionschedulemodel>();
                var equipmentsToUpdate = new List<Equipmentmodel>();
                var ordersToUpdate = new List<OrderModel>(); // 需要更新状态的订单
                var skippedOrderDetails = new List<(long OrderId, string Reason)>();
                var currentTime = DateTime.Now;

                // 遍历订单进行排程
                foreach (var order in pendingOrders)
                {
                    // 数据验证
                    if (order.Number <= 0)
                    {
                        skippedOrderDetails.Add((order.Id, "订单数量无效"));
                        continue;
                    }

                    // 查找最早可用的设备（支持多生产线并行）
                    var availableEquipment = FindEarliestAvailableEquipment(allEquipments, equipmentProcessMap, equipmentTimeline);
                    if (availableEquipment == null)
                    {
                        skippedOrderDetails.Add((order.Id, "无可用设备或工艺工序"));
                        continue;
                    }

                    // 从映射中获取该设备对应的工艺工序
                    if (!equipmentProcessMap.TryGetValue(availableEquipment.Id, out var processStep))
                    {
                        skippedOrderDetails.Add((order.Id, "设备无对应工艺工序"));
                        continue;
                    }

                    // 计算总耗时（分钟）
                    var totalTimeMinutes = order.Number * processStep.SpanTime;
                    if (totalTimeMinutes <= 0)
                    {
                        skippedOrderDetails.Add((order.Id, "工艺工序时间配置无效"));
                        continue;
                    }

                    // 获取该设备的计划开始时间和结束时间
                    var planStartTime = equipmentTimeline[availableEquipment.Id];
                    var planEndTime = planStartTime.AddMinutes(totalTimeMinutes);

                    // 实际时间比计划时间提前24小时
                    var actualStartTime = planStartTime.AddDays(-1);
                    var actualEndTime = planEndTime.AddDays(-1);

                    // 创建排程记录
                    var scheduleModel = new Productionschedulemodel
                    {
                        Id = YitIdHelper.NextId(),
                        Equipmentid = availableEquipment.Id,
                        Makestepid = processStep.Id,
                        OrderId = order.Id,
                        Plannumber = $"SCJH{(currentCount + scheduleModels.Count).ToString().PadLeft(6, '0')}",
                        Planstatetime = planStartTime,      // 计划开始时间
                        Planendtime = planEndTime,          // 计划结束时间
                        Statetime = actualStartTime,        // 实际开始时间（计划开始时间 - 24小时）
                        Endtime = actualEndTime,            // 实际结束时间（计划结束时间 - 24小时）
                        Planstate = 1, // 1：已排程
                        IsDel = false
                    };

                    scheduleModels.Add(scheduleModel);

                    // 更新订单状态为已排程（状态1）
                    order.Orderstatus = 1;
                    if (!ordersToUpdate.Contains(order))
                    {
                        ordersToUpdate.Add(order);
                    }

                    // 更新设备时间线（该设备的下次可用时间为本次结束后的第二天早上8点）
                    var nextAvailableTime = planEndTime.AddDays(1).Date.AddHours(8);
                    equipmentTimeline[availableEquipment.Id] = nextAvailableTime;

                    // 标记设备为占用状态（状态3：占用中）
                    if (availableEquipment.EquipmentStatus == 2)
                    {
                        availableEquipment.EquipmentStatus = 3;
                        if (!equipmentsToUpdate.Contains(availableEquipment))
                        {
                            equipmentsToUpdate.Add(availableEquipment);
                        }
                    }
                }

                // 批量插入排程记录
                if (!scheduleModels.Any())
                {
                    var reasons = string.Join("；", skippedOrderDetails.Select(x => $"订单{x.OrderId}：{x.Reason}"));
                    return APIResult<int>.Faile($"所有订单均无法排程。原因：{reasons}");
                }

                // 使用事务确保数据一致性
                var result = await productionRep.AddRangeAsync(scheduleModels);

                // 批量更新订单状态（状态0：待排程 → 状态1：已排程）
                if (ordersToUpdate.Any())
                {
                    await orderRep.UpdateRangeAsync(ordersToUpdate);
                }

                // 批量更新设备状态（状态2：空闲 → 状态3：占用中）
                if (equipmentsToUpdate.Any())
                {
                    await equipRep.UpdateRangeAsync(equipmentsToUpdate);
                }

                // 构建返回消息
                var usedEquipmentCount = scheduleModels.Select(x => x.Equipmentid).Distinct().Count();
                var message = BuildResultMessage(scheduleModels.Count, skippedOrderDetails, usedEquipmentCount, allEquipments.Count);

                return APIResult<int>.Ok(message, result);
            }
            catch (Exception ex)
            {
                return APIResult<int>.Faile($"排程失败：{ex.Message}");
            }
        }

        /// <summary>
        /// 查找最早可用的设备（负载均衡策略）
        /// 每次选择当前结束时间最早的设备，确保订单均匀分配到各个设备
        /// </summary>
        private Equipmentmodel FindEarliestAvailableEquipment(
            List<Equipmentmodel> equipments,
            Dictionary<long, Makestepmodel> equipmentProcessMap,
            Dictionary<long, DateTime> equipmentTimeline)
        {
            Equipmentmodel earliestEquipment = null;
            DateTime earliestTime = DateTime.MaxValue;

            foreach (var equipment in equipments)
            {
                // 必须有对应的工艺工序
                if (!equipmentProcessMap.ContainsKey(equipment.Id))
                    continue;

                // 找到当前结束时间最早的设备（负载最轻的设备）
                var availableTime = equipmentTimeline[equipment.Id];
                if (availableTime < earliestTime)
                {
                    earliestTime = availableTime;
                    earliestEquipment = equipment;
                }
            }

            return earliestEquipment;
        }

        /// <summary>
        /// 构建排程结果消息
        /// </summary>
        private string BuildResultMessage(int successCount, List<(long OrderId, string Reason)> skippedOrders, int usedEquipmentCount, int totalEquipmentCount)
        {
            if (!skippedOrders.Any())
            {
                return $"排程成功，共 {successCount} 个订单，使用 {usedEquipmentCount}/{totalEquipmentCount} 条生产线";
            }

            var skippedInfo = string.Join("；", skippedOrders.Take(3).Select(x => $"订单{x.OrderId}（{x.Reason}）"));
            var moreInfo = skippedOrders.Count > 3 ? $"等{skippedOrders.Count}个" : "";

            return $"排程成功 {successCount} 个订单（使用 {usedEquipmentCount}/{totalEquipmentCount} 条生产线），{skippedOrders.Count} 个订单跳过（{skippedInfo}{moreInfo}）";
        }
    }
}
